﻿using System;
using System.Data;
using System.Data.OleDb;
using System.IO;
using TemplateMethod.BubbleSorter.Template;

namespace TemplateMethod
{
    public class FtoCRaw
    {
        //public static void Main(string[] args)
        //{
        //    bool done = false;
        //    while (!done)
        //    {
        //        string fahrString = Console.In.ReadLine();
        //        if (fahrString == null || fahrString.Length == 0)
        //            done = true;
        //        else
        //        {
        //            double fahr = Double.Parse(fahrString);
        //            double celcius = 5.0 / 9.0 * (fahr - 32);
        //            Console.Out.WriteLine("F={0}, C={1}", fahr, celcius);
        //        }
        //    }
        //    Console.Out.WriteLine("ftoc exit");
        //}
    }

    #region Template Method Pattern - Application sample

    public abstract class Application
    {
        private bool isDone = false;

        protected abstract void Init();
        protected abstract void Idle();
        protected abstract void Cleanup();
        protected void SetDone()
        {
            isDone = true;
        }

        protected bool Done()
        {
            return isDone;
        }

        public void Run()
        {
            Init();
            while (!Done())
                Idle();
            Cleanup();
        }
    }

    public class FtoCTemplateMethod : Application
    {
        private TextReader input;
        private TextWriter output;

        //public static void Main(string[] args)
        //{
        //    new FtoCTemplateMethod().Run();
        //}

        protected override void Init()
        {
            input = Console.In;
            output = Console.Out;
        }

        protected override void Idle()
        {
            string fahrString = input.ReadLine();
            if (fahrString == null || fahrString.Length == 0)
                SetDone();
            else
            {
                double fahr = Double.Parse(fahrString);
                double celcius = 5.0 / 9.0 * (fahr - 32);
                output.WriteLine("F={0}, C={1}", fahr, celcius);
            }
        }

        protected override void Cleanup()
        {
            output.WriteLine("ftoc exit");
        }
    }

    #endregion Template Method Pattern
}

#region Template Method Pattern - Bubble Sorter

namespace TemplateMethod.BubbleSorter.NoTemplate
{
    public class BubbleSorter
    {
        static int operations = 0;

        public static int Sort(int[] array)
        {
            operations = 0;
            if (array.Length <= 1)
                return operations;

            for (int nextToLast = array.Length - 2; nextToLast >= 0; nextToLast--)
                for (int index = 0; index <= nextToLast; index++)
                    CompareAndSwap(array, index);

            return operations;
        }

        private static void Swap(int[] array, int index)
        {
            int temp = array[index];
            array[index] = array[index + 1];
            array[index + 1] = temp;
        }

        private static void CompareAndSwap(int[] array, int index)
        {
            if (array[index] > array[index + 1])
                Swap(array, index);
            operations++;
        }
    }
}

namespace TemplateMethod.BubbleSorter.Template
{
    public abstract class BubbleSorter
    {
        private int operations = 0;

        protected int length = 0;

        protected int DoSort()
        {
            operations = 0;
            if (length <= 1)
                return operations;

            for (int nextToLast = length - 2; nextToLast >= 0; nextToLast--)
                for (int index = 0; index <= nextToLast; index++)
                {
                    if (OutOfOrder(index))
                        Swap(index);
                    operations++;
                }

            return operations;
        }

        protected abstract void Swap(int index);
        protected abstract bool OutOfOrder(int index);
    }

    public class IntBubbleSorter : BubbleSorter
    {
        private int[] array = null;

        public int Sort(int[] theArray)
        {
            array = theArray;
            length = array.Length;
            return DoSort();
        }

        protected override void Swap(int index)
        {
            int temp = array[index];
            array[index] = array[index + 1];
            array[index + 1] = temp;
        }

        protected override bool OutOfOrder(int index)
        {
            return (array[index] > array[index + 1]);
        }
    }

    public class DoubleBubbleSorter : BubbleSorter
    {
        private double[] array = null;

        public int Sort(double[] theArray)
        {
            array = theArray;
            length = array.Length;
            return DoSort();
        }
        protected override void Swap(int index)
        {
            double temp = array[index];
            array[index] = array[index + 1];
            array[index + 1] = temp;
        }

        protected override bool OutOfOrder(int index)
        {
            return (array[index] > array[index + 1]);
        }
    }
}

public class TestBubbleSorter
{
    //public static void Main(string[] args)
    //{
    //    var intSorter = new IntBubbleSorter();
    //    var intsArray = new[] { 6, 4, 9, 3, 142, 2, 432 };

    //    var operationsCount = intSorter.Sort(intsArray);

    //    Console.WriteLine("Bubbles count: {0}", operationsCount);

    //    foreach (var i in intsArray)
    //    {
    //        Console.WriteLine(i);
    //    }

    //    Console.WriteLine();

    //    var doubleSorter = new DoubleBubbleSorter();
    //    var doublesArray = new[] { 0.11D, 0.42435D, 0.626D, 0.23425D, 0.24323D };

    //    operationsCount = doubleSorter.Sort(doublesArray);

    //    Console.WriteLine("Bubbles count: {0}", operationsCount);

    //    foreach (var d in doublesArray)
    //    {
    //        Console.WriteLine(d);
    //    }

    //    Console.ReadLine();
    //}
}

#endregion

#region Template Method Pattern - DAL

/// <summary>
/// MainApp startup class for Real-World
/// Template Design Pattern.
/// </summary>
class MainApp
{
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    static void Main()
    {
        DataAccessObject daoCategories = new Categories();
        daoCategories.ShowEntities();

        DataAccessObject daoProducts = new Products();
        daoProducts.ShowEntities();

        // Wait for user
        Console.ReadKey();
    }
}

abstract class DataAccessObject
{
    protected string connectionString;
    protected DataSet dataSet;

    public virtual void Connect()
    {
        // Make sure mdb is available to app
        connectionString = "provider=Microsoft.JET.OLEDB.4.0; " + "data source=..\\..\\..\\db_sample.mdb";
    }

    public abstract void Select();

    public abstract void Process();

    public virtual void Disconnect()
    {
        connectionString = "";
    }

    public void ShowEntities()
    {
        Connect();
        Select();
        Process();
        Disconnect();
    }
}

class Categories : DataAccessObject
{
    public override void Select()
    {
        string sql = "select CategoryName from Categories";
        OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
          sql, connectionString);

        dataSet = new DataSet();
        dataAdapter.Fill(dataSet, "Categories");
    }

    public override void Process()
    {
        Console.WriteLine("Categories ---- ");

        DataTable dataTable = dataSet.Tables["Categories"];
        foreach (DataRow row in dataTable.Rows)
        {
            Console.WriteLine(row["CategoryName"]);
        }
        Console.WriteLine();
    }
}

class Products : DataAccessObject
{
    public override void Select()
    {
        string sql = "select ProductName from Products";
        OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
          sql, connectionString);

        dataSet = new DataSet();
        dataAdapter.Fill(dataSet, "Products");
    }

    public override void Process()
    {
        Console.WriteLine("Products ---- ");
        DataTable dataTable = dataSet.Tables["Products"];
        foreach (DataRow row in dataTable.Rows)
        {
            Console.WriteLine(row["ProductName"]);
        }
        Console.WriteLine();
    }
}

#endregion